/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.dynasty.dynamic.scanner;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;

/**
 * Freemarker 模板引擎实现内存输出
 * @author dynasty yq.xiong0320@gmail.com
 * @version 1.0
 * @date 2021/9/2 10:54
 */
@Component
public class FreemarkerOutput2MemoryTemplateEngine extends AbstractTemplateEngine {

    private Configuration configuration;

    @Override
    public FreemarkerOutput2MemoryTemplateEngine init(ConfigBuilder configBuilder) {
        super.init(configBuilder);
        configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        configuration.setDefaultEncoding(ConstVal.UTF8);
        configuration.setClassForTemplateLoading(FreemarkerOutput2MemoryTemplateEngine.class, StringPool.SLASH + "templates");
        return this;
    }

    @Override
    public void writer(Map<String, Object> objectMap, String templatePath, String outputFile) throws Exception {
        // 适配ftl文件路径调整 -> src/main/resources/templates
        if (templatePath.startsWith("/")) {
            templatePath = templatePath.substring(templatePath.indexOf('/', 1) + 1);
        }
        Template template = configuration.getTemplate(templatePath);

        try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(byteArrayOutputStream, "utf-8")) {

            template.process(objectMap, outputStreamWriter);
            logger.debug(byteArrayOutputStream.toString("utf-8"));

            // 保存源代码到内存
            String qualifiedClassName = determineQualifiedClassName(templatePath, objectMap);
            CompileContext.SOURCE_CODE_MAP.putIfAbsent(qualifiedClassName, byteArrayOutputStream.toByteArray());
        }
        logger.debug("模板:" + templatePath + ";  文件:" + outputFile);
    }

    private String determineQualifiedClassName(String templatePath, Map<String, Object> objectMap) {
        if (templatePath.contains("entity")) {
            return ((Map) objectMap.get("package")).get("Entity").toString() + "." +  objectMap.get("entity").toString();
        }
        if (templatePath.contains("mapper")) {
            return ((Map) objectMap.get("package")).get("Mapper").toString() + "." +  objectMap.get("entity").toString() + "Mapper";
        }
        return "";
    }

    /**
     * 输出 java xml 文件
     */
    @Override
    public AbstractTemplateEngine batchOutput() {
        try {
            List<TableInfo> tableInfoList = getConfigBuilder().getTableInfoList();
            for (TableInfo tableInfo : tableInfoList) {
                Map<String, Object> objectMap = getObjectMap(tableInfo);
//                Map<String, String> pathInfo = getConfigBuilder().getPathInfo();
                TemplateConfig template = getConfigBuilder().getTemplate();

                objectMap.remove("superControllerClassPackage");
                objectMap.remove("superControllerClass");
                objectMap.remove("superEntityClass");
                tableInfo.getImportPackages().remove("你自己的父类实体,没有就不用设置!");

                // Mp.java
                String entityName = tableInfo.getEntityName();
                if (null != entityName) {
//                    String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + suffixJavaOrKt()), entityName);
//                    if (isCreate(FileType.ENTITY, entityFile)) {
                        writer(objectMap, templateFilePath(template.getEntity(getConfigBuilder().getGlobalConfig().isKotlin())), "");
//                    }
                }

                // 自定义内容
                InjectionConfig injectionConfig = getConfigBuilder().getInjectionConfig();
                if (null != injectionConfig) {
                    injectionConfig.initMap();
                    objectMap.put("cfg", injectionConfig.getMap());
                    List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
                    if (CollectionUtils.isNotEmpty(focList)) {
                        for (FileOutConfig foc : focList) {
                            if (isCreate(FileType.OTHER, foc.outputFile(tableInfo))) {
                                writer(objectMap, foc.getTemplatePath(), foc.outputFile(tableInfo));
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("无法创建文件，请检查配置信息！", e);
        }
        return this;
    }

    @Override
    public String templateFilePath(String filePath) {
        return filePath + ".ftl";
    }

    /**
     * 覆盖创建文件夹功能 -> do nothing
     * @return
     */
    @Override
    public AbstractTemplateEngine mkdirs() {
        return this;
    }
}
